#include "server.h"

CLIENT clients[MAXIMO_CLIENTS];
GRUPO grupos[MAXIMO_GRUPOS];
int n_clients = 0;
int n_grupos = 0;
int n_ligacoes = 0;
int n_msg_multi = 0;
int n_msg_broad = 0;
int n_msg_uni = 0;
int n_bytes = 0;
int background=0;
char logo[TAMANHO_MAXIMO];
sem_t mutex;
sem_t mutex2;

int encontraCliente(char * nick) {
	sem_wait(&mutex);
	int n=0;
	while (n<n_clients) {
		if(strcmp(clients[n].nick, nick)==0) {
			sem_post(&mutex);
			return n;
		}
		n++;
	}
	sem_post(&mutex);
	return -1;
} 

int encontraGrupo(char * nome) {
	sem_wait(&mutex2);
	int n=0;
	while (n<n_grupos) {
		if(strcmp(grupos[n].nome, nome)==0) {
			sem_post(&mutex2);
			return n;
		}
		n++;
	}
	sem_post(&mutex2);
	return -1;
} 

void sendMessageToAGroup(CLIENT * src, int groupID, MENSAGEM_FROM_SERVER * mensagem) {
	sem_wait(&mutex2);
	int n=0;
	
	while(n<grupos[groupID].nro_membros) {
		
		if (grupos[groupID].membros[n]->pid != src->pid) {
			int fd = open(grupos[groupID].membros[n]->msg_srv_to_cli, O_WRONLY);
			write(fd, mensagem, sizeof(MENSAGEM_FROM_SERVER));
			grupos[groupID].membros[n]->msg_multi_rec++;
			grupos[groupID].membros[n]->num_bytes += sizeof(char)*strlen(mensagem->msg);
			close(fd);
		}
		n++;
	}
	sem_post(&mutex2);
}

void sendMessageToAllButOne(CLIENT * src, MENSAGEM_FROM_SERVER * mensagem) {
	int n = 0;
	sem_wait(&mutex);
	while (n<n_clients) {
		
		if ((clients[n].pid != src->pid) && (clients[n].groupID == -1) && (strcmp(clients[n].nick_chat,"SEM_CHAT")==0) ) {
			int fd = open(clients[n].msg_srv_to_cli, O_WRONLY);
			write(fd, mensagem, sizeof(MENSAGEM_FROM_SERVER));
			clients[n].msg_broad_rec++;
			clients[n].num_bytes += sizeof(char)*strlen(mensagem->msg);
			close(fd);
		}
		n++;
	}
	sem_post(&mutex);
}

void sendMessageToClient(CLIENT * dest, MENSAGEM_FROM_SERVER * mensagem) {
	int n = 0;
	sem_wait(&mutex);
	while (n<n_clients) {
		
		if (clients[n].pid == dest->pid) {
			int fd = open(clients[n].msg_srv_to_cli, O_WRONLY);
			write(fd, mensagem, sizeof(MENSAGEM_FROM_SERVER));
			close(fd);
		}
		n++;
	}
	sem_post(&mutex);
}



int verificaNick(CLIENT * client) {
	//verifica se nao existe nenhum cliente com o mesmo nick
	int n = 0;
	sem_wait(&mutex);
	while (n<n_clients) {
		if (strcmp(clients[n].nick,client->nick)==0) {
			sem_post(&mutex);
			return 1;
		}
		n++;
	}
	sem_post(&mutex);
	return 0;
	
}


void sendInfoToClient(CLIENT * dest, INFO_TO_CLIENT * info) {
	//envia informacao para um determinado cliente
	int fd = open(dest->info_srv_to_cli, O_WRONLY);
	write(fd, info, sizeof(INFO_TO_CLIENT));
	close(fd);
}

void sendInfoToAllButOne(CLIENT * src, INFO_TO_CLIENT * info) {
	//envia informacao para todos os clientes (excepto o indicado)
	int n = 0;
	sem_wait(&mutex);
	while (n<n_clients) {
		
		if (clients[n].pid != src->pid) {
			int fd = open(clients[n].info_srv_to_cli, O_WRONLY);
			write(fd, info, sizeof(INFO_TO_CLIENT));
			close(fd);
		}
		n++;
	}
	sem_post(&mutex);
}


void sendInfoToAll(INFO_TO_CLIENT * info) {
	//envia informacao para todos os clientes
	sem_wait(&mutex);
	int n = 0;
	while (n<n_clients) {
			int fd = open(clients[n].info_srv_to_cli, O_WRONLY);
			write(fd, info, sizeof(INFO_TO_CLIENT));
			close(fd);
			n++;
	}
	sem_post(&mutex);
}

int InsertClientIntoGroup(CLIENT * cli, GRUPO * grupo) {
	
	sem_wait(&mutex2);
	int n=0;
	while (n<n_grupos) {
		if(strcmp(grupos[n].nome, grupo->nome)==0)
			break;
		n++;
	}
	if (n!=n_grupos) {
		grupos[n].membros[grupos[n].nro_membros] = &clients[encontraCliente(cli->nome)];
		grupos[n].nro_membros++;
		clients[encontraCliente(cli->nome)].groupID = n;
		sem_post(&mutex2);
		return 0;
	}
	
	//caso o grupo nao exista
	INFO_TO_CLIENT nao_ligou_a_grupo;
	strcpy(nao_ligou_a_grupo.mensagem, GRUPO_INEXISTENTE);
	strcpy(nao_ligou_a_grupo.mensagem_aux, grupo->nome);
	sendInfoToClient(cli,&nao_ligou_a_grupo);
	sem_post(&mutex2);
	return 1;
	
}

void RemoveClientFromGroup(CLIENT * cli, GRUPO * grupo) {
	
	sem_wait(&mutex2);
	int n=0, m=0;
	while (n<n_grupos) {
		if(strcmp(grupos[n].nome, grupo->nome)==0) {
			while(m<grupos[n].nro_membros) {
				if(strcmp(grupos[n].membros[m]->nick, cli->nick)==0) {
					clients[encontraCliente(cli->nick)].groupID = -1;
					while(m<grupos[n].nro_membros-1){
						grupos[n].membros[m] = grupos[n].membros[m+1];
						m++;}
					grupos[n].nro_membros--;
					break;
				}
			m++;
			}
		}
		n++;
	}
	sem_post(&mutex2);
}

void leave(CLIENT *client) {
	if(clients[encontraCliente(client->nick)].groupID != -1){
		INFO_TO_CLIENT saiu_do_grupo;
		strcpy(saiu_do_grupo.mensagem, LEFT_GROUP);
		strcpy(saiu_do_grupo.mensagem_aux, grupos[client->groupID].nome);
		sendInfoToClient(&clients[encontraCliente(client->nick)],&saiu_do_grupo);
		
		INFO_TO_CLIENT cliente_saiu_grupo;
		snprintf(cliente_saiu_grupo.mensagem, TAMANHO_MAXIMO, "%s%s%s", client->nick, AVISO_SAIDA_GRUPO, grupos[client->groupID].nome);
		sendInfoToAllButOne(&clients[encontraCliente(client->nick)], &cliente_saiu_grupo);
		RemoveClientFromGroup(&clients[encontraCliente(client->nick)], &grupos[client->groupID]);
		clients[encontraCliente(client->nick)].groupID=-1;
	}
			
	if(strcmp(clients[encontraCliente(client->nick)].nick_chat, "SEM_CHAT")){
		INFO_TO_CLIENT saiu_do_chat;
		strcpy(saiu_do_chat.mensagem, LEFT_CHAT);
		sendInfoToClient(&clients[encontraCliente(client->nick)],&saiu_do_chat);
				
		INFO_TO_CLIENT saiu_do_chat2;
		strcpy(saiu_do_chat2.mensagem, LEFT_CHAT);
		sendInfoToClient(&clients[encontraCliente(clients[encontraCliente(client->nick)].nick_chat)],&saiu_do_chat);
				
		strcpy(clients[encontraCliente(clients[encontraCliente(client->nick)].nick_chat)].nick_chat, "SEM_CHAT");
		strcpy(clients[encontraCliente(client->nick)].nick_chat, "SEM_CHAT");
				
	}
}


void printInfoToLog(char * message) {
	
	FILE *ficheiro;
	ficheiro = fopen(logo, "a");
	
	time_t tim = time(NULL);
	struct tm *tempo_actual = localtime(&tim);
	
	char buffer[TAMANHO_MAXIMO];
	snprintf(buffer, TAMANHO_MAXIMO, "(%02d:%02d:%02d) >> %s\n", tempo_actual->tm_hour, tempo_actual->tm_min, tempo_actual->tm_sec, message);
	fputs(buffer,ficheiro);
	fclose(ficheiro);
	
}

void printMessageToLog(MENSAGEM_FROM_SERVER * mensagem) {
	
	FILE *ficheiro;
	ficheiro = fopen(logo, "a");
	
	time_t tim = time(NULL);
	struct tm *tempo_actual = localtime(&tim);
	
	char buffer[TAMANHO_MAXIMO];
	char message[TAMANHO_MAXIMO];
	
	if (clients[encontraCliente(mensagem->nick)].groupID != -1) 
		snprintf(message, TAMANHO_MAXIMO, "%s para grupo[%s]", mensagem->nick, grupos[clients[encontraCliente(mensagem->nick)].groupID].nome);
	else if (strcmp(clients[encontraCliente(mensagem->nick)].nick_chat,"SEM_CHAT")!=0) 
		snprintf(message, TAMANHO_MAXIMO, "%s para %s ", mensagem->nick, clients[encontraCliente(mensagem->nick)].nick_chat);
	else
		strcpy(message, mensagem->nick);
	
	snprintf(buffer, TAMANHO_MAXIMO, "(%02d:%02d:%02d) %s >> %s\n", tempo_actual->tm_hour, tempo_actual->tm_min, tempo_actual->tm_sec, message, mensagem->msg);
	fputs(buffer,ficheiro);
	fclose(ficheiro);

}


void disconnectClient(CLIENT * client) {
	
	leave(client);
			INFO_TO_CLIENT disconnect;
			strcpy(disconnect.mensagem, DISCONNECT_MESSAGE);
			sendInfoToClient(&clients[encontraCliente(client->nick)],&disconnect); //envia mensagem para o cliente
			INFO_TO_CLIENT client_desligou;
			snprintf(client_desligou.mensagem, TAMANHO_MAXIMO, "%s%s", client->nick, CLIENT_DESLIGADO);
			sendInfoToAllButOne(&clients[encontraCliente(client->nick)],&client_desligou); //envia mensagem aos outros clientes
			printf("%s acabou de se desligar!\n", client->nick); //escreve no servidor
			
		
			char message[TAMANHO_MAXIMO];
			snprintf(message, TAMANHO_MAXIMO, "%s acabou de se desligar!", client->nick); 
				
			printInfoToLog(message);
			
			//elimina a FIFO e desliga o cliente
			unlink(clients[encontraCliente(client->nick)].info_srv_to_cli);
	
	//desliga o cliente pretendido e reordena os outros clientes
	int i = 0;
	while (client->pid != clients[i].pid)
		i++;
	while(i<n_clients-1){
		clients[i] = clients[i+1];
		i++;
	}
	n_clients--;
}

void * thr_msgFromClientToClients_func(void * arg) {

	CLIENT * cliente = ((CLIENT*) arg);
	
	COMANDO mensagemFromClient;
	int fd = open(cliente->msg_cli_to_srv, O_RDONLY);
	int n;
	do {
		n = read(fd, &mensagemFromClient, sizeof(COMANDO));
		if (n>0) {
			
			MENSAGEM_FROM_SERVER mensagem;
			
			if (clients[encontraCliente(cliente->nick)].groupID != -1) {	
				n_msg_multi++;
				strcpy(mensagem.msg,mensagemFromClient.msg);
				strcpy(mensagem.nick, mensagemFromClient.nick);
				n_bytes += sizeof(char)*strlen(mensagem.msg);
				sendMessageToAGroup(cliente, cliente->groupID, &mensagem);
				printMessageToLog(&mensagem);
				clients[encontraCliente(mensagem.nick)].msg_multi_env++;
				clients[encontraCliente(mensagem.nick)].num_bytes += sizeof(char)*strlen(mensagem.msg);
				
			}
			
			else if (strcmp(clients[encontraCliente(cliente->nick)].nick_chat,"SEM_CHAT") != 0) {
				n_msg_uni++;
				strcpy(mensagem.msg,mensagemFromClient.msg);
				strcpy(mensagem.nick, mensagemFromClient.nick);
				n_bytes += sizeof(char)*strlen(mensagem.msg);
				sendMessageToClient(&clients[encontraCliente(cliente->nick_chat)], &mensagem);
				printMessageToLog(&mensagem);
				clients[encontraCliente(mensagem.nick)].msg_uni_env++;
				clients[encontraCliente(mensagem.nick)].num_bytes += sizeof(char)*strlen(mensagem.msg);
				clients[encontraCliente(cliente->nick_chat)].msg_uni_rec++;
				clients[encontraCliente(cliente->nick_chat)].num_bytes += sizeof(char)*strlen(mensagem.msg);
			}
			
			else {
				n_msg_broad++;
				strcpy(mensagem.msg,mensagemFromClient.msg);
				strcpy(mensagem.nick, mensagemFromClient.nick);
				n_bytes += sizeof(char)*strlen(mensagem.msg);
				sendMessageToAllButOne(cliente, &mensagem);
				printMessageToLog(&mensagem);
				clients[encontraCliente(mensagem.nick)].msg_broad_env++;
				clients[encontraCliente(mensagem.nick)].num_bytes += sizeof(char)*strlen(mensagem.msg);
			}
		}
	
	} while (1 == 1);
}

void * thr_cmd_func(void * arg) {
	COMANDO cmd = (*(COMANDO*) arg);
	
	CLIENT client;
	client.pid = cmd.pid;
	strcpy(client.nick,cmd.nick);

	switch(cmd.id_comando) {
				
		case CONNECT: {
			n_ligacoes++;		
			strcpy(client.nome,cmd.nome);
			
			strcpy(client.email,cmd.email);
			client.groupID = -1;
			client.msg_broad_env=0;
			client.msg_multi_env=0;
			client.msg_uni_env=0;
			client.msg_broad_rec=0;
			client.msg_multi_rec=0;
			client.msg_uni_rec=0;
			client.num_bytes=0;
			time(&client.tempo);
			strcpy(client.info_srv_to_cli,cmd.info_srv_to_cli);
			strcpy(client.msg_srv_to_cli,cmd.msg_srv_to_cli);
			strcpy(client.msg_cli_to_srv,cmd.msg_cli_to_srv);	
			strcpy(client.nick_chat, "SEM_CHAT");
			
			mkfifo(client.info_srv_to_cli,0660);
			mkfifo(client.msg_cli_to_srv,0660);
			
			//verifica se pode adicionar o novo cliente
			if (n_clients == MAXIMO_CLIENTS) {
				INFO_TO_CLIENT servidor_cheio;
				strcpy(servidor_cheio.mensagem,SERVIDOR_CHEIO);
				sendInfoToClient(&client,&servidor_cheio);
			}
			//verifica se o cliente nao usa um nick existente
			else if (verificaNick(&client) == 1) {
				INFO_TO_CLIENT nick_invalido;
				strcpy(nick_invalido.mensagem,NICK_INVALIDO);
				sendInfoToClient(&client,&nick_invalido);
			}
			//adiciona o novo cliente
			else {				
				INFO_TO_CLIENT connect;
				strcpy(connect.mensagem, CONNECT_MESSAGE);
				sendInfoToClient(&client,&connect); //envia mensagem para o cliente
				INFO_TO_CLIENT client_entrou;
				snprintf(client_entrou.mensagem, TAMANHO_MAXIMO, "%s%s", client.nick, CLIENT_LIGADO);
				sendInfoToAllButOne(&client,&client_entrou); //envia mensagem aos outros clientes
				printf("%s acabou de se ligar!\n", client.nick); //escreve no servidor
				clients[n_clients] = client; //aloca o novo cliente
				n_clients++;
				
				char message[TAMANHO_MAXIMO];
				snprintf(message, TAMANHO_MAXIMO, "%s acabou de se ligar!", client.nick); //escreve no servidor
				
				printInfoToLog(message);
				
				pthread_t th;
				pthread_create(&th, NULL, thr_msgFromClientToClients_func, &clients[encontraCliente(client.nick)]);
			}
			break;
		}
		
		case DISCONNECT: {
			
			disconnectClient(&client);
			
			break;
		}
		
		case WHOIS: {
			
			INFO_TO_CLIENT dados_user;
			if (encontraCliente(cmd.msg)!=-1)
				snprintf(dados_user.mensagem, TAMANHO_MAXIMO, "Nome: %s\nEmail: %s", clients[encontraCliente(cmd.msg)].nome, clients[encontraCliente(cmd.msg)].email);
			else
				strcpy(dados_user.mensagem, USER_INEXISTENTE);
				
			sendInfoToClient(&clients[encontraCliente(client.nick)], &dados_user);
			break;
		}
		
		case NICK: {
			
			strcpy(client.nome, cmd.nome);
			
			if (verificaNick(&client) == 1) {
				INFO_TO_CLIENT nick_invalido;
				strcpy(nick_invalido.mensagem,NICK_INVALIDO2);
				sendInfoToClient(&clients[encontraCliente(client.nome)],&nick_invalido);
			}
			else{
				int i = 0;
				while (client.pid != clients[i].pid)
					i++;
					
				char antigo[TAMANHO_MAXIMO];
				strcpy(antigo, clients[i].nick);
				strcpy(clients[i].nick, client.nick);
		
				INFO_TO_CLIENT aviso_novo_nick, msg_cliente;
				snprintf(aviso_novo_nick.mensagem, TAMANHO_MAXIMO, "%s%s%s", antigo, CLIENT_NOVO_NICK, client.nick);
				strcpy(msg_cliente.mensagem, MUDAR_NICK);
				strcpy(msg_cliente.mensagem_aux, clients[i].nick);
				sendInfoToClient(&clients[i], &msg_cliente);
				sendInfoToAllButOne(&client,&aviso_novo_nick); //envia mensagem aos outros clientes
				printf("%s\n", aviso_novo_nick.mensagem); //escreve no servidor
				printInfoToLog(aviso_novo_nick.mensagem);
			}
			break;
		}

		case CREATE: {
			if (encontraGrupo(cmd.msg)==-1){
				GRUPO g;
				strcpy(g.nome, cmd.msg);
				g.nro_membros = 0;
				g.membros[g.nro_membros] = &clients[encontraCliente(client.nick)];
				g.nro_membros++;
				clients[encontraCliente(client.nick)].groupID = n_grupos;
				grupos[n_grupos] = g;
				n_grupos++;
						
				INFO_TO_CLIENT criou_grupo;
				strcpy(criou_grupo.mensagem, CREATED_GROUP);
				strcpy(criou_grupo.mensagem_aux, g.nome);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&criou_grupo);
				
				INFO_TO_CLIENT cliente_entrou_grupo;
				snprintf(cliente_entrou_grupo.mensagem, TAMANHO_MAXIMO, "%s%s%s", client.nick, AVISO_LIGACAO_GRUPO, g.nome);
				sendInfoToAllButOne(&clients[encontraCliente(client.nick)], &cliente_entrou_grupo);
				printInfoToLog(cliente_entrou_grupo.mensagem);
			}
			else {
				INFO_TO_CLIENT erro_grupo;
				strcpy(erro_grupo.mensagem, GRUPO_REPETIDO);
				strcpy(erro_grupo.mensagem_aux, cmd.msg);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&erro_grupo);
			}
			break;
		}
		
		case LIST_USERS: {
			INFO_TO_CLIENT lista;
			int i;
			for(i = 0; i<n_clients;i++){
				strcpy(lista.mensagem, clients[i].nick);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&lista);
			}
			break;
		}
		
		case LIST_GROUPS: {
			INFO_TO_CLIENT lista;
			int i;
			for(i = 0; i<n_grupos;i++){
				strcpy(lista.mensagem, grupos[i].nome);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&lista);
			}
			break;
		}

		case JOIN: {
			GRUPO group;
			strcpy(group.nome, cmd.msg);
			
			if(InsertClientIntoGroup(&clients[encontraCliente(client.nick)], &group)==0){

				INFO_TO_CLIENT ligou_a_grupo;
				strcpy(ligou_a_grupo.mensagem, JOINED_GROUP);
				strcpy(ligou_a_grupo.mensagem_aux, group.nome);
				
				
				char message[TAMANHO_MAXIMO];
				snprintf(message, TAMANHO_MAXIMO, "%s acabou de se juntar ao grupo %s", client.nick, group.nome); 
				
				printInfoToLog(message);
			
				
				sendInfoToClient(&clients[encontraCliente(client.nick)],&ligou_a_grupo);
				
				INFO_TO_CLIENT cliente_entrou_grupo;
				snprintf(cliente_entrou_grupo.mensagem, TAMANHO_MAXIMO, "%s%s%s", client.nick, AVISO_LIGACAO_GRUPO, group.nome);
				sendInfoToAllButOne(&clients[encontraCliente(client.nick)], &cliente_entrou_grupo);
			}
			break;
		}
		
		case MEMBERS: {
			INFO_TO_CLIENT membros;
			int n;
			for (n = 0; n < grupos[clients[encontraCliente(client.nick)].groupID].nro_membros; n++){
				strcpy(membros.mensagem, grupos[clients[encontraCliente(client.nick)].groupID].membros[n]->nome);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&membros);
			}
			break;
		}
		
		case LEAVE: {
			leave(&client);
			char message[TAMANHO_MAXIMO];
			snprintf(message, TAMANHO_MAXIMO, "%s acabou de voltar ao modo broadcast", client.nick); 
				
			printInfoToLog(message);
			
			break;
		}
		
		case CHAT: {
			INFO_TO_CLIENT entrou_em_chat;
			if (encontraCliente(cmd.msg)==-1){
				strcpy(entrou_em_chat.mensagem, USER_INEXISTENTE);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&entrou_em_chat);
			}
			
			else if (clients[encontraCliente(cmd.msg)].groupID != -1 || strcmp(clients[encontraCliente(cmd.msg)].nick_chat, "SEM_CHAT") != 0) {
				strcpy(entrou_em_chat.mensagem, CHAT_OCUPPIED);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&entrou_em_chat);
			}
			else {
				strcpy(clients[encontraCliente(client.nick)].nick_chat, cmd.msg);
				strcpy(clients[encontraCliente(cmd.msg)].nick_chat, client.nick);
				
				INFO_TO_CLIENT entrou_em_chat;
				strcpy(entrou_em_chat.mensagem, IN_CHAT);
				strcpy(entrou_em_chat.mensagem_aux, cmd.msg);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&entrou_em_chat);
				
				INFO_TO_CLIENT entrou_em_chat2;
				strcpy(entrou_em_chat2.mensagem, IN_CHAT);
				strcpy(entrou_em_chat2.mensagem_aux, client.nick);
				sendInfoToClient(&clients[encontraCliente(cmd.msg)],&entrou_em_chat2);
				
				INFO_TO_CLIENT users_entraram_em_chat;
				
				char message[TAMANHO_MAXIMO];
				snprintf(message, TAMANHO_MAXIMO, "%s%s%s", client.nick, AVISO_EXISTENCIA_CHAT, cmd.msg);
				
				printInfoToLog(message);
		
				int x=0;
				for(;x<n_clients;x++) 
					if ((strcmp(clients[x].nick, client.nick)!=0) && (strcmp(clients[x].nick, cmd.msg)!=0))
						sendInfoToClient(&clients[x],&users_entraram_em_chat);
			}
			break;
		}
		
		case STATS: {
			INFO_TO_CLIENT stats;
			snprintf(stats.mensagem, TAMANHO_MAXIMO, "%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d", NUM_CLIENTES, n_clients, NUM_LIGACOES, n_ligacoes, NUM_BROAD, n_msg_broad, NUM_MULTI, n_msg_multi, NUM_UNI, n_msg_uni,NUM_BYTES, n_bytes);
			sendInfoToClient(&clients[encontraCliente(client.nick)],&stats);
			break;
		}
		
		case MYSTATS: {
			INFO_TO_CLIENT mystats;
			time_t actual;
			double dif;
			time(&actual);
			dif = difftime (actual,clients[encontraCliente(client.nick)].tempo);
			snprintf(mystats.mensagem, TAMANHO_MAXIMO, "%s%.0f segundos\n%s%d\n%s%d", TEMPO_LIG, dif, CLI_NUM_BROAD_ENV, clients[encontraCliente(client.nick)].msg_broad_env, CLI_NUM_BROAD_REC, clients[encontraCliente(client.nick)].msg_broad_rec);
			sendInfoToClient(&clients[encontraCliente(client.nick)],&mystats);
			snprintf(mystats.mensagem, TAMANHO_MAXIMO, "%s%d\n%s%d", CLI_NUM_UNI_REC, clients[encontraCliente(client.nick)].msg_uni_rec, CLI_NUM_UNI_ENV, clients[encontraCliente(client.nick)].msg_uni_env);
			sendInfoToClient(&clients[encontraCliente(client.nick)],&mystats);
			snprintf(mystats.mensagem, TAMANHO_MAXIMO, "%s%d\n%s%d\n%s%d", CLI_NUM_MULTI_ENV, clients[encontraCliente(client.nick)].msg_multi_env, CLI_NUM_MULTI_REC, clients[encontraCliente(client.nick)].msg_multi_rec,CLI_NUM_BYTES, clients[encontraCliente(client.nick)].num_bytes);
			sendInfoToClient(&clients[encontraCliente(client.nick)],&mystats);
			break;
		}
		
		case KICK: {
			INFO_TO_CLIENT kick;
			if (encontraCliente(cmd.msg)==-1){
				strcpy(kick.mensagem, USER_INEXISTENTE);
				sendInfoToClient(&clients[encontraCliente(client.nick)],&kick);
			}
			else{
				snprintf(kick.mensagem, TAMANHO_MAXIMO, "Foi kickado do servidor!\n");
				sendInfoToClient(&clients[encontraCliente(cmd.msg)],&kick);
				disconnectClient(&clients[encontraCliente(cmd.msg)]);
			}
			break;
		}
		
		case SHUTDOWN: {
			int i;
			INFO_TO_CLIENT shutdown;
			snprintf(shutdown.mensagem, TAMANHO_MAXIMO, "O servidor irá encerrar dentro de 2 segundos!\n");
			sendInfoToClient(&clients[encontraCliente(client.nick)],&shutdown);
			sendInfoToAllButOne(&clients[encontraCliente(client.nick)], &shutdown);
			int n = n_clients;
			for (i=0;i<n;i++)
				disconnectClient(&clients[0]);
			printf("\n");
			exit(0);
			break;
		}
		
		default:
			break;
		
	}
	pthread_exit(0);
}

static void sigint_handler(int signo)
{
	int i;
	int n = n_clients;
	for (i=0;i<n;i++){
			disconnectClient(&clients[0]);
	}
	printf("\n");
	exit(0);
}

int main(int argc, char * argv[]){


	int i = 0;
	strcpy(logo, LOGFILE);
	while(i<argc){
		if(strcmp(argv[i],"-b")==0)
			background = 1;
		if(strcmp(argv[i],"-l")==0)
			strcpy(logo,argv[i+1]);
		i++;
		}
	if(argc != 4 && background == 1){
		printf( "Necessita de indicar o logfile: %s -b -l logfile\n", argv[0]);
		return -1;
	}

	int cmd_cli_to_srv;

	sem_init(&mutex, 0,1); // inicializa o semáforo para a lista dos users
	sem_init(&mutex2,0,1); // inicializa o semáforo para o lista de grupos

	if(signal(SIGINT, sigint_handler) < 0)
		return 1;

	mkfifo("/tmp/lrc_cmd_cli_to_srv",0660);
	
	do {
		cmd_cli_to_srv=open("/tmp/lrc_cmd_cli_to_srv",O_RDONLY);
		if (cmd_cli_to_srv==-1) sleep(1); 
	} while (cmd_cli_to_srv==-1);
	
	int n;
	do {
		COMANDO cmd;
		n = read(cmd_cli_to_srv, &cmd, sizeof(COMANDO));
	
		if (n>0) {
			pthread_t th;
			pthread_create(&th, NULL, thr_cmd_func, &cmd);
		}
	
	}while (1==1); 		

	close(cmd_cli_to_srv);
	
	return 0;
}
